<!DOCTYPE html>
<html lang="zh-CN">





<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/apple-touch-icon.png">
  <link rel="icon" type="image/png" href="/img/favicon.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <meta name="description" content="">
  <meta name="author" content="yhs0092">
  <meta name="keywords" content="ServiceComb-Java-Chassis,K8S,microservice,docker,JVM">
  <title>Docker容器内部署Java微服务的内存限制问题 ~ 遥·海·时 的博客</title>

  <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/5.10.2/css/all.min.css"  >
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css"  >
<link rel="stylesheet" href="https://cdn.staticfile.org/mdbootstrap/4.8.9/css/mdb.min.css"  >
<link rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/3.0.1/github-markdown.min.css"  >

<link rel="stylesheet" href="//at.alicdn.com/t/font_1067060_qzomjdt8bmp.css">



  <link rel="stylesheet" href="/lib/prettify/github-v2.min.css"  >

<link rel="stylesheet" href="/css/main.css"  >


  <link rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css"  >


<meta name="generator" content="Hexo 4.2.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>遥·海·时 的博客</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          <li class="nav-item">
            <a class="nav-link" href="/">Home</a>
          </li>
        
          
          
          <li class="nav-item">
            <a class="nav-link" href="/archives/">Archives</a>
          </li>
        
          
          
          <li class="nav-item">
            <a class="nav-link" href="/categories/">Categories</a>
          </li>
        
          
          
          <li class="nav-item">
            <a class="nav-link" href="/tags/">Tags</a>
          </li>
        
          
          
          <li class="nav-item">
            <a class="nav-link" href="/about/">About</a>
          </li>
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>


</nav>

    <div class="view intro-2" id="background"
         style="background: url('/img/post-banner.jpg')no-repeat center center;
           background-size: cover;
           background-attachment: fixed;">
      <div class="full-bg-img">
        <div class="mask rgba-black-light flex-center">
          <div class="container text-center white-text fadeInUp">
            <span class="h2" id="subtitle">
              
            </span>

            
              <br>
              
                <p class="mt-3">
                  <i class="fas fa-calendar-alt" aria-hidden="true"></i>&nbsp;
                  星期六, 十一月 24日 2018, 10:42 上午
                </p>
              

              <p>
                
                  
                  &nbsp;<i class="far fa-chart-bar"></i>
                  <span class="post-count">
                    2.5k 字
                  </span>&nbsp;
                

                
                  
                  &nbsp;<i class="far fa-clock"></i>
                  <span class="post-count">
                      9 分钟
                  </span>&nbsp;
                

                
                  <!-- 不蒜子统计文章PV -->
                  
                  &nbsp;<i class="far fa-eye" aria-hidden="true"></i>&nbsp;
                  <span id="busuanzi_container_page_pv">
                    <span id="busuanzi_value_page_pv"></span> 次
                  </span>&nbsp;
                
              </p>
            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="py-5 z-depth-3" id="board">
        <div class="post-content mx-auto" id="post">
          <div class="markdown-body">
            <p>警惕JVM占用内存超过K8S容器内存配额限制，进而导致微服务进程被关闭的问题。</p>
<a id="more"></a>
<h1 id="Docker容器内部署Java微服务的内存限制问题"><a href="#Docker容器内部署Java微服务的内存限制问题" class="headerlink" title="Docker容器内部署Java微服务的内存限制问题"></a>Docker容器内部署Java微服务的内存限制问题</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>前两天有同事发现，通过华为云 ServiceStage 的流水线部署基于模板创建的 CSEJavaSDK demo 服务时，会在容器启动过程中报错。初步排查是由于 JVM 占用的内存超出了 docker 内存配额的上限，导致容器被 kill 掉。于是我们需要排查一下问题出在哪里，为什么以前没有这类问题，而现在却发生了。</p>
<h2 id="基本定位"><a href="#基本定位" class="headerlink" title="基本定位"></a>基本定位</h2><p>要确定 docker 容器内存超限问题的直接原因并不难。直接进入docker容器，执行 <code>top</code> 命令，我们发现宿主机是一台8核16G的机器，而且 docker 并不会屏蔽这些信息，也就是 JVM 会认为自己工作于一台 16G 内存的机器上。而查看 demo 服务的 Dockerfile，发现运行服务时并没有对 JVM 的内存进行任何限制，于是 JVM 会根据默认的设置来工作 —— 最大堆内存为物理内存的1/4(这里的描述并不完全准确，因为 JVM 的默认堆内存大小限制比例其实是根据物理内存有所变化的，具体内容请自行搜索资料)，而基于模板创建的 ServiceStage 流水线，在部署应用堆栈的时候会把 docker 容器的内存配额默认设置为 512M，于是容器就会在启动的时候内存超限了。至于以前没有碰到过这种问题的原因，只是因为以前没将这么高规格的 ECS 服务器用于流水线部署应用堆栈。</p>
<p>在查询过相关资料后，我们找到了两种问题解决方案，一个是直接在 jar 包运行命令里加上 <code>-Xmx</code> 参数来指定最大堆内存，不过这种方式只能将 JVM 堆内存限制为一个固定的值；另一个方法是在执行 jar 包时加上 <code>-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap</code> 参数，让 JVM 能够感知到docker容器所设置的 <code>cgroup</code> 限制，相应地调整自身的堆内存大小，不过这个特性是 JDK 8u131 以上的版本才具备的。</p>
<p>最终，我们提醒 ServiceStage 流水线的同学将 CSEJavaSDK demo 的创建模板做了改进，在 Dockerfile 中将打包的基础镜像版本由原先的 <code>java:8u111-jre-alpine</code> 升级为了 <code>openjdk:8u181-jdk-alpine</code>，并且在运行服务 jar 包的命令中加上了 <code>-Xmx256m</code> 参数。问题至此已经解决了。</p>
<h2 id="进一步的探究"><a href="#进一步的探究" class="headerlink" title="进一步的探究"></a>进一步的探究</h2><p>虽然问题已经解决，但是在好奇心的驱使下，我还是打算自己找个 demo 实际去触发一下问题，另外看看从网上搜到的解决方法到底好不好用 : )</p>
<h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><ol>
<li><p>创建云上工程</p>
<p><img src="/img/blog/MemoryConsumingOfJvmInDocker/create_cloud-base_project.PNG" srcset="/img/loading.gif" alt=""></p>
<p>首先需要在华为云 ServiceStage 创建一个云上工程。</p>
<p>在 ServiceStage -&gt; 应用开发 -&gt; 微服务开发 -&gt; 工程管理 -&gt; 创建云上工程中，选择“基于模板创建”，语言选择 Java， 框架选择 <code>CSE-Java (SpringMVC)</code>，部署系统选择“云容器引擎CCE”，给你的云上工程取一个名字，比如<code>test-memo-consuming</code>，最后选择存放代码的仓库，就可以完成云上工程的创建了。</p>
<p>之后云上工程会根据你的选项自动地生成脚手架代码，上传到你指定的代码仓库中，并且为你创建一条流水线，完成代码编译、构建、打包、归档镜像包的操作，并且使用打好的 docker 镜像包在 CCE 集群中部署一个应用堆栈。</p>
<blockquote>
<p>创建云上工程和流水线不是本文的重点，我就不详细讲操作了 : )。同一个应用堆栈的实例可以部署多个，在这里为了实验方便就按照默认值1个来部署。</p>
</blockquote>
<p><img src="/img/blog/MemoryConsumingOfJvmInDocker/demo_service_instance.PNG" srcset="/img/loading.gif" alt=""><br>由于云上工程已经改进了脚手架代码的模板，不会再出现内存超限的问题，所以我们现在能看到 demo 服务已经正常的跑起来，微服务实例已经注册到服务中心了。</p>
<p><img src="/img/blog/MemoryConsumingOfJvmInDocker/curl_helloworld.PNG" srcset="/img/loading.gif" alt=""><br>登录到 demo 服务所部署的容器，使用<code>curl</code>命令可以调用 demo 服务的 helloworld 接口，可以看到此时服务已经可以正常工作。</p>
</li>
<li><p>增加实验代码</p>
<p>为了能够触发微服务实例消耗更多的内存，我在项目代码中增加了如下接口，当调用<code>/allocateMemory</code>接口时，微服务实例会不停申请内存，直到 JVM 抛出 OOM 错误或者容器内存超限被 kill 掉。</p>
<pre><code class="java">private HashMap&lt;String, long[]&gt; cacheMap = new HashMap&lt;&gt;();

@GetMapping(value = &quot;/allocateMemory&quot;)
public String allocateMemory() {
 LOGGER.info(&quot;allocateMemory() is called&quot;);
 try {
   for (long i = 0; true; ++i) {
     cacheMap.put(&quot;key&quot; + i, new long[1024 * 1024]);
   }
 } catch (Throwable t) {
   LOGGER.info(&quot;allocateMemory() gets error&quot;, t);
 }
 return &quot;allocated&quot;;
}</code></pre>
<p>此时用来打镜像包的基础镜像是<code>openjdk:8u181-jdk-alpine</code>，jar 包启动命令中加上了<code>-Xmx256m</code>参数。</p>
<p>执行流水线，应用堆栈部署成功后，调用<code>/allocateMemory</code>接口触发微服务实例消耗内存，直到 JVM 抛出 OOM 错误，可以在 ServiceStage -&gt; 应用上线 -&gt; 应用管理中选择相应的应用，点击进入概览页面，查看应用使用内存的情况。</p>
<p><img src="/img/blog/MemoryConsumingOfJvmInDocker/deploy_normal.PNG" srcset="/img/loading.gif" alt=""><br>应用使用的内存从 800M+ 陡然下降的时间点就是我重新打包部署的时间，而之后由于调用<code>/allocateMemory</code>接口，内存占用量上升到了接近 400M，并且在这个水平稳定了下来，显示<code>-Xmx256m</code>参数发挥了预期的作用。</p>
</li>
</ol>
<h3 id="复现问题"><a href="#复现问题" class="headerlink" title="复现问题"></a>复现问题</h3><p>现在将 demo 工程中的 Dockerfile 修改一下，将基础镜像改为 <code>java:8u111-jre-alpine</code>，并且删除启动命令中的<code>-Xmx256m</code>参数，将其提交为<code>noLimit_oldBase</code>分支，推送到代码仓库中。然后编辑流水线，将 source 阶段的任务所使用的代码分支改为<code>noLimit_oldBase</code>分支，保存并重新运行流水线，将新的代码打包部署到应用堆栈中。</p>
<div align=center><img src="/img/blog/MemoryConsumingOfJvmInDocker/deploy_noLimit_oldBase.PNG" srcset="/img/loading.gif" width="50%" height="50%"/></div>
在微服务实例列表中查询到新的微服务实例的 endpoint IP 后，调用`/allocateMemory`接口，观察内存情况，内存从接近 400M 突然掉下去一下，然后又上升到约 450M 的时间点就是修改代码后的微服务实例部署成功的时间点，之后内存占用量突然下跌就是因为调用`/allocateMemory`接口导致容器内存超限被 kill 掉了。

<p>如果你事先使用<code>docker logs -f</code>命令查看容器日志的话，那么日志大概是这个样子的</p>
<pre><code>2018-11-23 15:40:04,920  INFO SCBEngine:152 - receive MicroserviceInstanceRegisterTask event, check instance Id...
2018-11-23 15:40:04,920  INFO SCBEngine:154 - instance registry succeeds for the first time, will send AFTER_REGISTRY event.
2018-11-23 15:40:04,925  WARN VertxTLSBuilder:116 - keyStore [server.p12] file not exist, please check!
2018-11-23 15:40:04,925  WARN VertxTLSBuilder:136 - trustStore [trust.jks] file not exist, please check!
2018-11-23 15:40:04,928  INFO DataFactory:62 - Monitor data sender started. Configured data providers is {com.huawei.paas.cse.tcc.upload.TransactionMonitorDataProvider,com.huawei.paas.monitor.HealthMonitorDataProvider,}
2018-11-23 15:40:04,929  INFO ServiceCenterTask:51 - read MicroserviceInstanceRegisterTask status is FINISHED
2018-11-23 15:40:04,939  INFO TestmemoconsumingApplication:57 - Started TestmemoconsumingApplication in 34.81 seconds (JVM running for 38.752)
2018-11-23 15:40:14,943  INFO AbstractServiceRegistry:258 - find instances[1] from service center success. service=default/CseMonitoring/latest, old revision=null, new revision=28475010.1
2018-11-23 15:40:14,943  INFO AbstractServiceRegistry:266 - service id=8b09a7085f4011e89f130255ac10470c, instance id=8b160d485f4011e89f130255ac10470c, endpoints=[rest://100.125.0.198:30109?sslEnabled=true]
2018-11-23 15:40:34,937  INFO ServiceCenterTaskMonitor:39 - sc task interval changed from -1 to 30
2018-11-23 15:47:03,823  INFO SPIServiceUtils:76 - Found SPI service javax.ws.rs.core.Response$StatusType, count=0.
2018-11-23 15:47:04,657  INFO TestmemoconsumingImpl:39 - allocateMemory() is called
Killed</code></pre><p>可以看到<code>allocateMemory</code>方法被调用，然后 JVM 还没来得及抛出 OOM 错误，整个容器就被 kill 掉了。</p>
<blockquote>
<p>这里也给大家提了一个醒：<strong>不要以为自己的服务容器能启动起来就万事大吉了</strong>，如果没有特定的限制，JVM 会在运行时继续申请堆内存，也有可能造成内存用量超过 docker 容器的配额！</p>
</blockquote>
<h3 id="让-JVM-感知cgroup限制"><a href="#让-JVM-感知cgroup限制" class="headerlink" title="让 JVM 感知cgroup限制"></a>让 JVM 感知<code>cgroup</code>限制</h3><p>前文提到还有另外一种方法解决 JVM 内存超限的问题，这种方法可以让 JVM 自动感知 docker 容器的 <code>cgroup</code> 限制，从而动态的调整堆内存大小，感觉挺不错的。我们也来试一下这种方法，看看效果如何 ; )</p>
<p>回到demo项目代码的<code>master</code>分支，将 Dockerfile 中启动命令参数的<code>-Xmx256m</code>替换为<code>-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap</code>，提交为<code>useCGroupMemoryLimitForHeap</code>分支，推送到代码仓库里。再次运行流水线进行构建部署。</p>
<div align=center><img src="/img/blog/MemoryConsumingOfJvmInDocker/deploy_useCGroupMemoryLimitForHeap.PNG" srcset="/img/loading.gif" width="50%" height="50%"/></div>
等 demo 服务部署成功后，再次调用`/allocateMemory`接口，容器的内存占用情况如上图所示（最右边的那一部分连续曲线），内存上升到一定程度后，JVM 抛出了 OOM 错误，没有继续申请堆内存。看来这种方式也是有效果的。

<p>不过，仔细观察容器的内存占用情况，可以发现容器所使用的内存仅为不到 300M，而我们对于这个容器的内存配额限制为 512M，也就是还有 200M+ 是闲置的，并不会被 JVM 利用。这个利用率，比起上文中直接设置<code>-Xmx256m</code>的内存利用率要低 : ( 。推测是因为 JVM 并不会感知到自己是部署在一个 docker 容器里的，所以它把当前的环境当成一个物理内存只有 512M 的物理机，按照比例来限制自己的最大堆内存，另一部分就被闲置了。</p>
<blockquote>
<p>如此看来，如果想要充分利用自己的服务器资源，还是得多花一点功夫，手动调整好<code>-Xmx</code>参数。</p>
</blockquote>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a href="https://royvanrijn.com/blog/2018/05/java-and-docker-memory-limits/" target="_blank" rel="noopener" title="Java and Docker, the limitations">Java and Docker, the limitations</a></li>
<li><a href="https://developers.redhat.com/blog/2017/03/14/java-inside-docker/" target="_blank" rel="noopener" title="Java inside docker: What you must know to not FAIL - RHD Blog">Java inside docker: What you must know to not FAIL</a></li>
</ul>

            <hr>
          </div>
          <br>
          <div>
            <p>
            
              <span>
                <i class="iconfont icon-inbox"></i>
                
                  <a class="hover-with-bg" href="/categories/%E8%BD%AF%E4%BB%B6%E6%8A%80%E6%9C%AF">软件技术</a>
                  &nbsp;
                
                  <a class="hover-with-bg" href="/categories/%E8%B8%A9%E5%9D%91">踩坑</a>
                  &nbsp;
                
              </span>&nbsp;&nbsp;
            
            
              <span>
                <i class="iconfont icon-tag"></i>
                
                  <a class="hover-with-bg" href="/tags/microservice">microservice</a>
                
                  <a class="hover-with-bg" href="/tags/ServiceComb-Java-Chassis">ServiceComb-Java-Chassis</a>
                
                  <a class="hover-with-bg" href="/tags/K8S">K8S</a>
                
                  <a class="hover-with-bg" href="/tags/docker">docker</a>
                
                  <a class="hover-with-bg" href="/tags/JVM">JVM</a>
                
              </span>
            
            </p>
            
              <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a href="https://zh.wikipedia.org/wiki/Wikipedia:CC_BY-SA_3.0%E5%8D%8F%E8%AE%AE%E6%96%87%E6%9C%AC" target="_blank" rel="nofollow noopener noopener">CC BY-SA 3.0协议</a> 。转载请注明出处！</p>
            
          </div>
        </div>
      </div>
    </div>
    <div class="d-none d-lg-block col-lg-2 toc-container">
      
  <div id="toc">
    <p class="h4"><i class="far fa-list-alt"></i>&nbsp;目录</p>
    <div id="tocbot"></div>
  </div>

    </div>
  </div>
</div>

<!-- custom -->


<!-- Comments -->
<div class="col-lg-7 mx-auto nopadding-md">
  <div class="container comments mx-auto" id="comments">
    
  </div>
</div>

    
  </main>

  
    <a class="z-depth-1" id="scroll-top-button" href="#" role="button">
      <i class="fa fa-chevron-up scroll-top-arrow" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  <footer class="mt-5">
  <div class="text-center py-3">
    <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><b>Hexo</b></a>
    <i class="iconfont icon-love"></i>
    <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"> <b>Fluid</b></a>
    <br>

    
  
    <!-- 不蒜子统计PV -->
    
    &nbsp;<span id="busuanzi_container_site_pv">总访问量 
          <span id="busuanzi_value_site_pv"></span> 次</span>&nbsp;
  
  
    <!-- 不蒜子统计UV -->
    
    &nbsp;<span id="busuanzi_container_site_uv">总访客数 
            <span id="busuanzi_value_site_uv"></span> 人</span>&nbsp;
  
  <br>



    

  </div>
</footer>

<!-- SCRIPTS -->
<script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js" ></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js" ></script>
<script src="https://cdn.staticfile.org/mdbootstrap/4.8.9/js/mdb.min.js" ></script>
<script src="/js/main.js" ></script>


  <script src="/js/lazyload.js" ></script>



  
    <script src="https://cdn.staticfile.org/tocbot/4.8.0/tocbot.min.js" ></script>
  
  <script src="/js/post.js" ></script>



  <script src="https://cdn.staticfile.org/smooth-scroll/16.1.0/smooth-scroll.min.js" ></script>



  <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>


<!-- Plugins -->


  

  

  

  

  




  <script src="https://cdn.staticfile.org/prettify/r298/prettify.min.js" ></script>
  <script>
    $(document).ready(function () {
      $('pre').addClass('prettyprint  linenums');
      prettyPrint();
    })
  </script>



  <script src="https://cdn.staticfile.org/typed.js/2.0.10/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "Docker容器内部署Java微服务的内存限制问题&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script src="https://cdn.staticfile.org/anchor-js/4.2.0/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "left",
      visible: "false",
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script src="/js/local-search.js" ></script>
  <script>
    var path = "/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      getSearchFile(path);
      this.onclick = null
    }
  </script>



  <script src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <script>
    $("#post img:not(.no-zoom img, img[no-zoom])").each(
      function () {
        var element = document.createElement("a");
        $(element).attr("data-fancybox", "images");
        $(element).attr("href", $(this).attr("src"));
        $(this).wrap(element);
      }
    );
  </script>







</body>
</html>
